home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
355_02
/
slk2.exe
/
SPP
/
TOK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-09
|
10KB
|
516 lines
/*
New Sherlock Preprocessor -- Token parsing routines.
source: tok.c
started: October 7, 1985
version:
July 18, 1988
February 16, 1989
periods removed from error messages.
June 22, 1989
backslash-newline logic removed because sysnext()
now removes all backslash-newline combinations.
June 26, 1989
bug fix in skip_comment().
PUBLIC DOMAIN SOFTWARE
Sherlock, including the SPP, SDEL and SDIF programs, was placed in
the public domain on June 15, 1991, by its author,
Edward K. Ream
166 North Prospect Ave.
Madison, WI 53705.
(608) 257-0802
Sherlock may be used for any commercial or non-commercial purpose.
DISCLAIMER OF WARRANTIES
Edward K. Ream (Ream) specifically disclaims all warranties,
expressed or implied, with respect to this computer software,
including but not limited to implied warranties of merchantability
and fitness for a particular purpose. In no event shall Ream be
liable for any loss of profit or any commercial damage, including
but not limited to special, incidental consequential or other damages.
*/
#include "spp.h"
/* Declare internal variables and routines. */
static int is_base_digit (int);
static void scan_number (int);
static en_tokens t_int (void);
/*
Return >= 0 if ch is a digit in the indicated base.
Otherwise, return -1.
*/
static int
is_base_digit(base)
int base;
{
TRACECH("is_base_digit");
if (ch >= '0' && ch <= '9') {
RETURN_INT("is_base_digit", ch - '0');
}
else if (base != 16) {
RETURN_INT("is_base_digit", -1);
}
else if (ch >= 'a' && ch <= 'f') {
RETURN_INT("is_base_digit", ch - 'a' + 10);
}
else if (ch >= 'A' && ch <= 'F') {
RETURN_INT("is_base_digit", ch - 'A' + 10);
}
else {
RETURN_INT("is_base_digit", -1);
}
}
/*
Get value of a string of digits into t_value.
Continue until a non base digit is found.
*/
static void
scan_number(base)
int base;
{
int result;
TRACECH("scan_number");
t_value = 0;
while ( (result = is_base_digit(base)) != -1) {
t_value = ((long)base * t_value) + (long) result;
sysnext();
}
LEAVE("scan_number");
}
/*
Scan past a comment. Allow nested comments if nest_flag is TRUE.
Surprisingly, this routine needs to be as fast as possible.
*/
void
skip_comment(void)
{
register int clevel;
int start_line;
char line [LONG_DIGITS];
TRACECH("skip_comment");
/* Save starting line number for run-on comments. */
start_line = t_line;
clevel = 1;
/* Do not buffer the comment. */
syshflush();
hold_flag = FALSE;
for (;;) {
switch (ch) {
case END_FILE:
conv2s(start_line, line);
err2("File ends in a comment starting at line ", line);
hold_flag = TRUE;
RETURN_VOID("skip_comment");
case '\n':
/* Keep track of line numbering. */
sysnext();
/*
Bump the line count and output a newline
if this is used in a standalone preprocessor.
Do NOT allow directives here.
*/
bump_line();
/* Bug fix: 6/26/89 do NOT call begin_line!! */
/* --- begin_line(FALSE); --- */
first_tok = TRUE;
continue;
case '/':
sysnext();
if (ch == '*') {
sysnext();
if (nest_flag) {
clevel++;
}
}
continue;
case '*':
sysnext();
if (ch == '/') {
sysnext();
if (--clevel == 0) {
hold_flag = TRUE;
RETURN_VOID("skip_comment");
}
}
continue;
default:
sysnext();
}
}
}
/*
Copy an identifier into symbol[] and its length in the global t_length.
Surprisingly, this routine should be as fast as possible.
*/
void
t_id(symbol, max_length)
char * symbol;
int max_length;
{
int length = 0;
ENTER_TRACE("t_id", printf("(%p, %d)\n", symbol, max_length));
max_length--;
while (isid2(ch) && length < max_length) {
*symbol++ = ch;
length++;
sysnext();
}
*symbol = '\0';
t_length = length;
if (length >= max_length) {
error("Identifier too long");
}
LEAVE("t_id");
}
/*
Parse an integer constant (octal, decimal or hexadecimal) or float.
Put the value in t_value if it is an integer.
dot_flag is TRUE if a decimal point has been seen.
Return the token type (INT_TOK, LONG_TOK, FLOAT_TOK).
Legal integer forms: ddd, 0ddd, 0xddd
Legal float forms: xxx.yyyE+zzz
+-zzz is optional
one of xxx and yyy may be omitted
one of . and E may be omitted
*/
en_tokens
t_number(dot_flag)
bool dot_flag;
{
en_tokens result;
bool need_exp = FALSE;
TRACECH("t_number");
/* Defaults. */
t_value = 0;
if (dot_flag) {
goto frac_part;
}
/* Integer part. */
result = t_int();
if (ch == '.') {
sysnext();
goto frac_part;
}
else if (ch == 'e' || ch == 'E') {
goto exp_part;
}
else {
RETURN_INT("t_number", result);
}
/* Fraction part. */
frac_part:
t_int();
exp_part:
if (ch == 'e' || ch == 'E') {
need_exp = TRUE;
sysnext();
}
if (ch == '+' || ch == '-') {
need_exp = TRUE;
sysnext();
}
if (ch >= '0' && ch <= '9') {
t_int();
}
else if (need_exp) {
error("Ill formed floating constant");
}
if (ch == 'l' || ch == 'L' || ch == 'f' || ch == 'F') {
sysnext();
}
RETURN_INT("t_number", FLOAT_TOK);
}
static en_tokens
t_int()
{
TRACECH("t_int");
/* Leading 0 or 0x changes base. */
if (ch == '0') {
sysnext();
if (ch == 'x' || ch == 'X') {
sysnext();
scan_number(16);
}
else if (isdigit(ch)) {
scan_number(8);
}
else {
/* Lone '0'. */
t_value = 0;
}
}
else {
scan_number(10);
}
if (ch == 'l' || ch == 'L') {
sysnext();
if(ch == 'u' || ch == 'U') {
sysnext();
}
RETURN_INT("t_int", LONG_TOK);
}
else if (ch == 'u' || ch == 'U') {
sysnext();
if (ch == 'l' || ch == 'L') {
RETURN_INT("t_int", LONG_TOK);
}
else {
RETURN_INT("t_int", INT_TOK);
}
}
else {
RETURN_INT("t_int", INT_TOK);
}
}
/*
Copy a string into out[] and puts its length in the global t_length.
Copy the opening or closing delimiters if the copy_flag is TRUE.
This is used to parse both strings and character constants.
*/
void
t_string(out, max_out, copy_flag)
register char * out; /* The output buffer. */
int max_out; /* The size of out[]. */
bool copy_flag; /* Copy the delimiters if copy_flag is TRUE. */
{
register int length;
int start_line;
char * start_string;
char line [10];
int delim;
TRACECH("t_string");
/* Save starting line number for error messages. */
start_line = t_line;
start_string = out;
/* Handle the opening single or double quote */
delim = ch;
sysnext();
length = 0;
if (copy_flag) {
*out++ = delim;
length++;
}
max_out--;
while (length < max_out) {
switch(ch) {
case END_FILE:
case '\n':
goto runon1;
case '"':
case '\'':
if (ch == delim) {
sysnext();
if(copy_flag) {
*out++ = delim;
length++;
}
*out++ = '\0';
t_length = length;
TRACEP("t_string", printf("<%s>\n",
start_string));
RETURN_VOID("t_string");
}
else{
*out++ = ch;
length++;
sysnext();
}
continue;
case '\\':
sysnext();
if (ch == END_FILE) {
goto runon1;
}
#ifdef BACKSLASH_NEWLINE
else if (ch == '\n') {
/* Ignore back slash and newline. */
t_line++;
sysnext();
}
#endif
else {
*out++ = '\\';
*out++ = ch;
length += 2;
sysnext();
}
continue;
default:
*out++ = ch;
length++;
sysnext();
}
}
conv2s(start_line, line);
err3("String starting at line ", line, " is too long");
*out = '\0';
t_length = length;
RETURN_VOID("t_string");
runon1:
*out = '\0';
err3("String crosses a line: \"", start_string, "\"");
t_length = length;
LEAVE("t_string");
}
/*
Parse a string (including delimiters) from in[] to out.
Return the length of the ORIGINAL string.
*/
int
in_string(in, out, max_out)
char * in; /* The output buffer */
char * out; /* The output buffer. */
int max